/*
********************************************************************************************
* 
* this class allow to communicate with Sillaj time tracker application
* 
* you must specified user / password / url sillaj application folder
* 
*
*
********************************************************************************************
*/

package models
{
    import events.SillajConnectionEvent;
    import events.SillajEvent;
    
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.HTTPStatusEvent;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.net.URLRequestMethod;
    import flash.net.URLVariables;

    public class SillajModel extends EventDispatcher
    {
        


/*
/////////////////////
    PROPERTIES
/////////////////////
*/        
        /*user in sillaj DB*/
        private var _user:String ;
        
        /* password in sillaj DB*/
        private var _password:String ;
        
        /* url of the sillaj folder ( http://localhost/sillaj/ )*/
        private var _urlSillajFolder:String ;
        
        /* urlLoader to cmmunicate with server*/
        private var urlLoader:URLLoader ;
        
        /*to communicate with the server*/
        private var urlRequest:URLRequest ;
        
        private var urlVariables:URLVariables ;
        
        
        
        /*to send a request after login*/
        private var currentMethod:Function ;
        
        /*the current project selected*/
        private var currentProject:Object ;
        
        /*the current task*/
        private var currentTask:Object ;
        
        
        /*elements of an event*/
         private var timStart:String ;
         private var timEnd:String ;
         private var timDuration:String ;
         private var strRem:String ;
         private var datEvent:Date ;
        
        
        
/*
/////////////////////
    METHODS
/////////////////////
*/        
        
        
        /**
        * constructor
        * @param user string
        * @param password string
        * @param url folder sillaj string
        */ 
        public function SillajModel( user:String = '', password:String = '', urlSillajFolder:String = '' ):void
        {
            _user                = user ;
            _password        = password ;
            _urlSillajFolder = urlSillajFolder  ;   
            
            urlLoader = new URLLoader( ) ;
        }
        
        
        public function set user ( value:String ):void
        {
            _user = value ;
        }
        
        public function set password ( value:String ):void
        {
            _password = value ;
        }
        
        
        public function get urlSillajFolder( ):String
        {
            return _urlSillajFolder ;
        }
        
        public function set urlSillajFolder ( value:String ):void
        {
            /*si le dernier caractère de l'URL n'est pas /, on l'ajoute*/
           if(  value.substring( value.length - 1, value.length ) != '/' )
           { 
                value = value + "/" ;
           }
               
            _urlSillajFolder = value ;
        }                
        
        
        /**
        * check if user / password and url folder are fills
        * @return Boolean 
        */ 
        private function paramsFills( ):Boolean
        {
            if( _user != '' && _password != '' && _urlSillajFolder != '' )
            {
                return true ;
            }
            else
            {
                return false ;
            }
        }
        
        
        /**
        * test simplement si avec les paramètres de connexions on arrive à contacter le serveur
        */ 
        public function checkConnection( ):void
        {
            currentMethod = emptyFunction ;
            
            login( ) ;
        }
        /**
        * fonction qui ne sert à rien, juste à faire tourner le script de login seul
        */ 
        private function emptyFunction( ):void
        {
            return ;
        }
        
        
        /**
        * login the user
        * appelée systématiquement avant chaque méthode 
        */ 
        public function login( ):void
        {
            urlLoader = new URLLoader( ) ;
            
            urlRequest = new URLRequest( _urlSillajFolder + "login_xmlhttp.php" ) ;
            
            urlVariables = new URLVariables( ) ;
            urlVariables.strUserId      = _user ;
            urlVariables.strPassword = _password ;            
            
            urlRequest.data = urlVariables ;
            
            urlRequest.method = URLRequestMethod.POST ;
            
            urlLoader.addEventListener( Event.COMPLETE, login_completeHandler ) ;
            urlLoader.addEventListener( SecurityErrorEvent.SECURITY_ERROR, login_securityErrorHandler ) ;
            urlLoader.addEventListener( HTTPStatusEvent.HTTP_STATUS, login_httpStatusHandler ) ;
            urlLoader.addEventListener( IOErrorEvent.IO_ERROR, login_ioErrorHandler ) 
            
            urlLoader.load( urlRequest ) ;
        }
        
        /**
        * login complete
        * test de la longeur de la chaîne retournée
        * si supérieure à 4, c'est qu'il y a un soucis puisque le PHP a levé une erreur et qu'on récupére une page html complète
        */ 
        private function login_completeHandler( e:Event ):void
        {
            e.target.removeEventListener( Event.COMPLETE, login_completeHandler ) ;
           
           if( e.target.data.length < 5 )
           {
                dispatchEvent( new SillajConnectionEvent( SillajConnectionEvent.LOGIN_SUCCESS, _user, _password, _urlSillajFolder ) ) ;
           }
           else
           {
               var errorMessage:String = parseSillajError( e.target.data ) ;
               dispatchEvent( new SillajConnectionEvent( SillajConnectionEvent.LOGIN_FAIL, _user, _password, _urlSillajFolder, errorMessage ) ) ;
           }
           
           currentMethod( ) ;
        }
        
        
        /**
        * va recuperer dans la page HTML retournée par Sillaj, le message d'erreur
        * pour le trouver, on recherche la balise utilisant la classe error
        * 
        * exemple : 
        * <p class="error">Authentification impossible. Vérifiez le login et le mot de passe</p>
        */
        private function parseSillajError( message:String ):String
        {
            trace( message ) ;
           /*le +14 correspond à la longeur de la chaîne recherché, ça permet de trouver directement le message*/
           var errorStartPosition:uint = message.indexOf( 'class="error">' ) + 14 ;
           var errorEndPosition:uint   = message.indexOf( "</p>", errorStartPosition ) ;
           
           return message.substring( errorStartPosition, errorEndPosition )  ;
        }
        
        
        
        private function login_httpStatusHandler( e:HTTPStatusEvent ):void
        {
            //trace( e ) ;
            //trace( e.status ) ;
        }
        
        private function login_ioErrorHandler( e:IOErrorEvent ):void
        {
            dispatchEvent( new SillajConnectionEvent( SillajConnectionEvent.LOGIN_FAIL, _user, _password, _urlSillajFolder, e.text ) ) ;
        }
        
        private function login_securityErrorHandler( e:SecurityErrorEvent ):void
        {
            dispatchEvent( new SillajConnectionEvent( SillajConnectionEvent.LOGIN_FAIL, _user, _password, _urlSillajFolder, e.text ) ) ;
        }
        
        
        /**
        * return projects of the connected user
        */  
        public function getProject( ):void
        {
                
                currentMethod = getProject_afterLogin ;
                login( ) ;            
        }


        private function getProject_afterLogin( ):void
        {
                urlRequest = new URLRequest( _urlSillajFolder + "getProject_xmlhttp.php" ) ;
                
                urlRequest.method = URLRequestMethod.POST ;
                
                urlLoader.addEventListener( Event.COMPLETE, getProject_completeHandler ) ;
                urlLoader.load( urlRequest ) ;
        }

        /**
        * decoupage du retour
        * le format n'est pas adapté à une lecture directe, je passe donc pas un découpage manuel
        */ 
        private function getProject_completeHandler( e:Event ):void
        {
            e.target.removeEventListener( Event.COMPLETE, getProject_completeHandler ) ;
            
            var arResult:Array = transformSillajArray( e.target.data ) ;
            
            dispatchEvent( new SillajEvent( SillajEvent.COMPLETE, arResult ) ) ; 
        }
        
        
        /**
        * recupere les taches d'un projet donné en paramètres
        */
        public function getTask( project:Object ):void
        {
            currentMethod = getTask_afterLogin ;
            currentProject   = project ;
            
            login( ) ;    
        }
         
         /**
         * retourne la liste des taches d'un projet
         */ 
         private function getTask_afterLogin( ):void
         {
                urlVariables = new URLVariables( ) ;
                urlVariables.intProjectId  = currentProject.id ;
                
                urlRequest = new URLRequest( _urlSillajFolder + "getTask_xmlhttp.php" ) ;
                
                urlRequest.method = URLRequestMethod.GET ;
                urlRequest.data       = urlVariables ;
                
                urlLoader.addEventListener( Event.COMPLETE, getTask_completeHandler ) ;
                urlLoader.load( urlRequest ) ;
         }
         
         private function getTask_completeHandler( e:Event ):void
         {
            e.target.removeEventListener( Event.COMPLETE, getTask_completeHandler ) ;
            
            var arResult:Array = transformSillajArray( e.target.data ) ;
            dispatchEvent( new SillajEvent( SillajEvent.COMPLETE, arResult ) ) ;
         }
         
         
         
         /**
         * ajoute un évènement sur un projet et une tache donnée
         */
         public function addEvent( project:Object, task:Object, timStart:String, timEnd:String, timDuration:String, strRem:String, datEvent:Date ):void
         {
            currentMethod = addEvent_afterLogin ;
            currentProject   = project ;
            currentTask      = task ;
            
            this.timStart        = timStart ;
            this.timEnd         = timEnd ;
            this.timDuration = timDuration ;
            this.strRem         = strRem ;
            this.datEvent       = datEvent ;
            
            login( ) ;
         } 
         
         private function addEvent_afterLogin( ):void
         {
                urlVariables = new URLVariables( ) ;
                urlVariables.intProjectId  = currentProject.id ;
                urlVariables.intTaskId     = currentTask.id ;
                
                urlVariables.timStart        = this.timStart ;
                urlVariables.timEnd          = this.timEnd ;
                urlVariables.timDuration  = this.timDuration ;

                urlVariables.strRem          = noAccent( this.strRem ) ;
                
                /*on met la date dans le format attendu par Sillaj : YYYY-MM-DD*/
                urlVariables.datEvent        = this.datEvent.getFullYear() + "-" + ( uint( this.datEvent.getMonth() ) + 1 ) + "-" + this.datEvent.getDate() ;

                urlRequest = new URLRequest( _urlSillajFolder + "index.php" ) ;
                
                urlRequest.method  = URLRequestMethod.POST ;
                urlRequest.data       = urlVariables ;
                
                urlLoader.addEventListener( Event.COMPLETE, addEvent_completeHandler ) ;
                urlLoader.load( urlRequest ) ;
         }
         
         private function addEvent_completeHandler( e:Event ):void
         {
             e.target.removeEventListener( Event.COMPLETE, addEvent_completeHandler ) ;
             dispatchEvent( new SillajEvent( SillajEvent.COMPLETE, null ) ) ;
         }
         
         /**
         * fonction qui supprime les accents d'une chaine de caracteres
         * nécessaire car flash utilise de l'utf8 alors que le script php de sillaj de l'iso
         * @param chaine avec caracteres speciaux String
         * @return chaine sans caracteres speciaux String
         */
        private function noAccent(source : String) : String
        {
            source = source.replace(/[àáâãäå]/g, "a");
            source = source.replace(/[ÀÁÂÃÄÅ]/g, "A");
            source = source.replace(/[èéêë]/g, "e");
            source = source.replace(/[ËÉÊÈ]/g, "E");
            source = source.replace(/[ìíîï]/g, "i");
            source = source.replace(/[ÌÍÎÏ]/g, "I");
            source = source.replace(/[ðòóôõöø]/g, "o");
            source = source.replace(/[ÐÒÓÔÕÖØ]/g, "O");
            source = source.replace(/[ùúûü]/g, "u");
            source = source.replace(/[ÙÚÛÜ]/g, "U");
            source = source.replace(/[ýýÿ]/g, "y");
            source = source.replace(/[ÝÝŸ]/g, "Y");
            source = source.replace(/[ç]/g, "c");
            source = source.replace(/[Ç]/g, "C");
            source = source.replace(/[ñ]/g, "n");
            source = source.replace(/[Ñ]/g, "N");
            source = source.replace(/[š]/g, "s");
            source = source.replace(/[Š]/g, "S");
            source = source.replace(/[ž]/g, "z");
            source = source.replace(/[Ž]/g, "Z");
            source = source.replace(/[æ]/g, "ae");
            source = source.replace(/[Æ]/g, "AE");
            source = source.replace(/[œ]/g, "oe");
            source = source.replace(/[Œ]/g, "OE");
           
            return source;
        }
         
         
         /**
         * fonction qui transforme le tableau retourné par sillaj en tableau (Array) d'objets actionscript
         * chaque objet à un attribut id et name
         */
         private function transformSillajArray( str:String ):Array
         {
            var array:Array =  str.split( "Array" )  ;
            var detail:Array ;
            
            var arResult:Array = new Array( ) ;
            var obj:Object  ;
            
            
            for (var i:uint = 2 ; i < array.length ; i++ )
            {
                str = array[i] ;
                //on prend ce qui est entre les parenthèses
                str = str.substring( 1, str.indexOf( ")") ) ;
                //on separe les 2 élements
                detail = str.split( "," ) ;
                obj = new Object( ) ;
                obj.id      = detail[0] ;
                obj.name = detail[1] ;
                
                //on enleve les apostrophes
                obj.name = obj.name.substring( 2, obj.name.length - 1 );
                
                //si le projet est partagé, on a un asterisque au départ avec un espace derrière
                //ici on l'enlève
                if( obj.name.substring( 0, 2 ) == '* ' )
                {
                    obj.name = obj.name.substring( 2 );
                }
                
                arResult.push( obj ) ;     
            }
            
            return arResult ;
         } 
        
    }
}